﻿using BinAnalysisHelp;
using DevExpress.XtraEditors;
using Newtonsoft.Json;
using SerialPortHelperLib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using XChip_Common;
using XChipTool.Enties;

namespace XChipTool
{
    public partial class IntelligenceSettings : DevExpress.XtraEditors.XtraForm
    {

        public SerialPort sPortTemp;
        /// <summary>
        /// 记录usb 是否打开的状态
        /// </summary>
        public bool IsUsbOpen { get; set; } = false;
        /// <summary>
        /// 设置宽和高
        /// </summary>
        int _width = 0; int _height = 0;

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        public IntelligenceSettings()
        {
            InitializeComponent();
        }

        private void simpleButton3_Click(object sender, EventArgs e)
        {
            UpdateMonitorLabel(monitorLab, sPortTemp);
        }
        #region 刷新尺寸信息方法

        /// <summary>
        /// 更新监控标签的显示内容，基于串口或I2C配置。
        /// </summary>
        /// <param name="monitorLab">用于显示监控信息的标签。</param>
        /// <param name="sPortTemp">当前使用的串口。</param>
        public void UpdateMonitorLabel(LabelControl monitorLab, SerialPort sPortTemp)
        {
            // 检查配置值以确定使用的接口类型
            if (GetConfigValue("IsSerial") == "USB" || GetConfigValue("IsI2C") == "1")
            {
                UpdateLabelForUSBOrI2C(monitorLab, sPortTemp);
            }
            else
            {
                UpdateLabelForSerialPort(monitorLab, sPortTemp);
            }
        }

        /// <summary>
        /// 更新监控标签，适用于USB或I2C接口。
        /// </summary>
        /// <param name="monitorLab">用于显示监控信息的标签。</param>
        /// <param name="sPortTemp">串口对象（未使用但保留以匹配签名）。</param>
        private void UpdateLabelForUSBOrI2C(LabelControl monitorLab, SerialPort sPortTemp)
        {
            uint pValue = 0x0;
            uint pfps = 0x0;

            // 检查是否为I2C接口
            if (GetConfigValue("IsI2C") == "1")
            {
                // 这里可以添加I2C相关代码
                // pValue = (uint)SerialSend.ReadRegister(BinHelp.CurrentSize, sPortTemp);
                // pfps = (uint)SerialSend.ReadRegister(0x200065cc, sPortTemp);
            }
            else
            {
                // 对于USB接口，依据系统指针大小选择合适的方法
                bool isSuccess = IntPtr.Size == 8
                    ? ReadUsbRegisters64(ref pValue, ref pfps)
                    : ReadUsbRegisters86(ref pValue, ref pfps);

                // 发送读取命令
                SerialSend.Sendser("R:0x" + (BinHelp.CurrentSize).ToString("X2"), pValue.ToString("X2"));
            }

            // 从读取的值中解析出高16位和低16位
            var chang = (int)(pValue >> 16); // 获取高16位  
            var kuang = (int)(pValue & 0xFFFF); // 获取低16位  
            int fps = (pfps != 0) ? (int)(10000000 / pfps) : 0; // 计算帧率
            _width = chang;
            _height = kuang;
            // 更新监控标签的文本
            monitorLab.Text = $"{chang} * {kuang} {fps}fps";
        }

        /// <summary>
        /// 读取USB寄存器，适用于64位系统。
        /// </summary>
        private bool ReadUsbRegisters64(ref uint pValue, ref uint pfps)
        {
            bool isSuccess = true;
            isSuccess &= XChipUSB.UsbRegisterRead64(BinHelp.CurrentSize, ref pValue, true);
            isSuccess &= XChipUSB.UsbRegisterRead64(0x200065cc, ref pfps, true);
            return isSuccess;
        }

        /// <summary>
        /// 读取USB寄存器，适用于32位系统。
        /// </summary>
        private bool ReadUsbRegisters86(ref uint pValue, ref uint pfps)
        {
            bool isSuccess = true;
            isSuccess &= XChipUSB.UsbRegisterRead86(BinHelp.CurrentSize, ref pValue, true);
            isSuccess &= XChipUSB.UsbRegisterRead86(0x200065cc, ref pfps, true);
            return isSuccess;
        }

        /// <summary>
        /// 更新监控标签，适用于串口接口。
        /// </summary>
        /// <param name="monitorLab">用于显示监控信息的标签。</param>
        /// <param name="sPortTemp">当前使用的串口。</param>
        private void UpdateLabelForSerialPort(LabelControl monitorLab, SerialPort sPortTemp)
        {
            // 检查串口是否打开
            if (!sPortTemp.IsOpen)
            {
                // DevExpress.XtraEditors.XtraMessageBox.Show("可用端口未打开");
                return;
            }

            uint temp = (uint)SerialSend.ReadRegister(BinHelp.BootSettingIdx, sPortTemp);
            if (BinHelp.lspList != null)
            {
                var lspModel = BinHelp.lspList.Find(c => c.SettingHex == temp);
                if (lspModel != null)
                {
                    monitorLab.Text = $"{lspModel.tName}-{lspModel.vName}";
                }
            }
        }

        /// <summary>
        /// 获取指定键的配置值。
        /// </summary>
        /// <param name="strKey">配置项的键名。</param>
        /// <returns>配置项的值。</returns>
        private string GetConfigValue(string strKey)
        {
            var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            var settings = configFile.AppSettings.Settings;

            return settings[strKey]?.Value; // 使用?.避免空引用异常
        }
        #endregion


        #region 打开文件方法
        /// <summary>
        /// 打开文件对话框，让用户选择文件，并返回所选文件的路径。
        /// </summary>
        /// <param name="filter">文件类型过滤器，例如"所有文件(*.h)|*.h"</param>
        /// <returns>所选文件的路径，如果未选择则返回空字符串。</returns>
        public string OpenFileDialog(string filter)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                // 设置文件类型
                openFileDialog.Filter = filter;
                // 设置默认文件类型显示顺序
                openFileDialog.FilterIndex = 1;
                // 保存对话框是否记忆上次打开的目录
                openFileDialog.RestoreDirectory = true;

                // 显示对话框并判断用户是否选择了文件
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    return openFileDialog.FileName; // 返回所选文件的路径
                }
            }
            return string.Empty; // 如果用户未选择任何文件，返回空字符串
        }
        #endregion

        #region 按钮事件

        private void simpleButton1_Click(object sender, EventArgs e)
        {
            string selectedFilePath = OpenFileDialog("所有文件(*.txt)|*.txt");

            if (!string.IsNullOrEmpty(selectedFilePath))
            {
                textEdit1.Text = selectedFilePath; // 将所选文件路径设置到文本框中
                registerCommonValues = new List<RegisterValue>();
                registerCommonValues =   WriteRegistersFromFile(textEdit1.Text);
                //LoadRegistersFromTextBoxes();
            }
            else
            {
                MessageBox.Show("未选择任何文件。");
            }
        }

        private void simpleButton4_Click(object sender, EventArgs e)
        {
            string selectedFilePath = OpenFileDialog("所有文件(*.txt)|*.txt");

            if (!string.IsNullOrEmpty(selectedFilePath))
            {
                memoEdit1.Text = selectedFilePath; // 将所选文件路径设置到文本框中
                registerSettingValues = new List<RegisterValue>();
                registerSettingValues = WriteRegistersFromFile(memoEdit1.Text);
                string result = ExtractResolution(selectedFilePath);
                settingLab.Text = result;
                //LoadRegistersFromTextBoxes();
            }
            else
            {
                MessageBox.Show("未选择任何文件。");
            }
        }

        /// <summary>
        /// 从输入字符串中提取分辨率（格式为宽度x高度）。
        /// </summary>
        /// <param name="input">要解析的输入字符串。</param>
        /// <returns>提取的分辨率字符串，格式为"宽度x高度"，如果未找到则返回null。</returns>
        public string ExtractResolution(string input)
        {
            // 定义正则表达式，匹配格式为"数字x数字"
            string pattern = @"(\d+)x(\d+)";
            Match match = Regex.Match(input, pattern);

            if (match.Success)
            {
                return match.Value; // 返回匹配的字符串
            }

            return null; // 如果没有找到匹配，返回null
        }

        #endregion

        #region 文本处理成地址和值
        private List<RegisterValue> registerCommonValues;
        private List<RegisterValue> registerSettingValues;
        private List<RegisterValue> registerBinValues;
        // 从文件中读取寄存器设置
        public List<RegisterValue> WriteRegistersFromFile(string filePath)
        {
            List<RegisterValue> list = new List<RegisterValue>();
            UInt32 baseAddr = 0x0; // 基地址

            // 使用 StreamReader 读取文件
            using (StreamReader reader = new StreamReader(filePath, Encoding.GetEncoding("gb2312")))
            {
                // 循环读取文件中的每一行
                while (reader.Peek() > -1)
                {
                    string line = reader.ReadLine()?.Trim().Replace('，', ',').Replace(" ", ""); // 读取并修剪行
                    

                    RegisterValue registerValue = new RegisterValue
                    {
                        Note = line // 保存原始行作为备注
                    };

                   
                    // 正则表达式
                    string pattern = @"0x([0-9a-fA-F]+),0x([0-9a-fA-F]+)";

                    // 使用正则表达式匹配
                    Match match = Regex.Match(line, pattern);
                    if (match.Success)
                    {
                        // 提取地址和值
                        string addrHex = match.Groups[1].Value; // 地址部分
                        string valueHex = match.Groups[2].Value; // 值部分

                        // 将地址和值转换为 UInt32
                        UInt32 addr = Convert.ToUInt32(addrHex, 16);
                        UInt32 value = Convert.ToUInt32(valueHex, 16);

                        // 根据地址类型处理
                        if (addrHex.Equals("fffd", StringComparison.OrdinalIgnoreCase))
                        {
                            baseAddr = (value & 0xff) << 24; // 处理 0xfffd
                        }
                        else if (addrHex.Equals("fffe", StringComparison.OrdinalIgnoreCase))
                        {
                            baseAddr = (baseAddr & 0xff000000) + ((value & 0xff) << 16); // 处理 0xfffe
                        }
                        else
                        {
                            registerValue.BaseAddr = baseAddr;
                            registerValue.Addr = addr;
                            registerValue.Address = baseAddr + (addr & 0xffff); // 计算最终地址
                            registerValue.Value = value;
                        }
                    }

                    list.Add(registerValue); // 添加到列表
                }
            }

            // 输出结果到桌面文件
            string desktopPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "register_results.txt");
            using (StreamWriter writer = new StreamWriter(desktopPath))
            {
                foreach (var item in list)
                {
                    writer.WriteLine($"{item.Note}, Addr: {item.Addr:X}, BaseAddr: {item.BaseAddr:X}, Address: {item.Address:X}, Value: {item.Value:X}");
                }
            }

            return list;
        }


        #endregion

        private void simpleButton2_Click(object sender, EventArgs e)
        {
            //LoadRegistersFromTextBoxes();
            DevExpress.XtraEditors.XtraMessageBox.Show("融合导入文件成功！");
        }

        

        private void simpleButton5_Click(object sender, EventArgs e)
        {
            try
            {
                if (_width == 0 && _height == 0)
                {
                    DevExpress.XtraEditors.XtraMessageBox.Show("请刷新出图尺寸！");
                    return;
                }

                // 检查 settingLab.Text 是否不包含 _width 或 _height
                if (!settingLab.Text.Contains(_width.ToString()) || !settingLab.Text.Contains(_height.ToString()))
                {
                    DevExpress.XtraEditors.XtraMessageBox.Show("Setting尺寸和出图尺寸不同，请检查Setting文件是否正确");
                    return;
                }

                // 检查设备配置，如果是 USB 设备且已打开，或是 I2C 配置为 "1"
                if ((GetConfigValue("IsSerial") == "USB") || GetConfigValue("IsI2C") == "1")
                {
                    // 读取4个寄存器的值
                    uint temp0 = (uint)SerialSend.ReadRegister(BinHelp.BinToLength, sPortTemp, true);
                    uint temp1 = (uint)SerialSend.ReadRegister(BinHelp.BinToLength + 1, sPortTemp, true);
                    uint temp2 = (uint)SerialSend.ReadRegister(BinHelp.BinToLength + 2, sPortTemp, true);
                    uint temp3 = (uint)SerialSend.ReadRegister(BinHelp.BinToLength + 3, sPortTemp, true);

                    // 构造保存路径
                    var SavePath = string.Format("{0}\\Lib\\xc151_Bin\\Xchip_Output_{1}.bin", Application.StartupPath, DateTime.Now.ToString("yyyyMMddHHmmss"));

                    // 将读取的寄存器值转换为二进制文件长度
                    var binLength = Convert.ToUInt32($"{temp3:X2}{temp2:X2}{temp1:X2}{temp0:X2}", 16);

                    // 检查文件长度是否有效
                    if (binLength == 0xFFFFFFFF)
                    {
                        WaitBefore.Close();
                        DevExpress.XtraEditors.XtraMessageBox.Show("bin文件长度读取失败！");
                        return;
                    }

                    // 根据系统架构调用相应的方法读取文件
                    if (IntPtr.Size == 8)
                    {
                        XChipUSB.UsbFlashQuickReadFile64(SavePath, 0x0, binLength);
                    }
                    else
                    {
                        XChipUSB.UsbFlashQuickReadFile86(SavePath, 0x0, binLength);
                    }

                    // 设置最大重试次数
                    int maxRetries = 5;
                    int retryCount = 0;

                    // 尝试检查文件是否存在且内容不为空
                    while (retryCount < maxRetries)
                    {
                        // 检查文件是否存在且内容不为空
                        if (File.Exists(SavePath) && new FileInfo(SavePath).Length > 0)
                        {
                            Console.WriteLine("文件存在且不为空");
                            break; // 文件已正确写入，退出循环
                        }

                        // 等待一段时间再重试
                        Thread.Sleep(2000); // 2000毫秒 = 2秒  
                        retryCount++;
                    }

                    logger.Debug("开始文件解析");

                    // 解析 xc151binparsing 列表
                    xc151_exManager xcmex = new xc151_exManager();
                    var xclist = JsonConvert.DeserializeObject<List<xc151binparsing>>(xcmex.GetListToXc151Binparsing())
                                      .OrderBy(c => c.Id).ToList();

                    // 初始化列表
                    List<BinBase> BinList = new List<BinBase>();
                    List<LoadSettingParse> lspList = new List<LoadSettingParse>();
                    List<SettingFileIDInfo> usbList = new List<SettingFileIDInfo>();

                    // 打开并解析 Bin 文件
                    BinUtilsHelp.OpenBinFile(SavePath, xclist, ref BinList, ref lspList, ref usbList, IsUsbOpen);
                    logger.Debug("结束文件解析");

                    // 检查是否存在可以解析的配置文件
                    if (BinList.Count(c => !string.IsNullOrEmpty(c.note) && c.note.Contains("setting区1_31_") && !c.note.Contains("_en") && !c.module.Contains("Header")) <= 0)
                    {
                        // WaitBefore.Close();
                        DevExpress.XtraEditors.XtraMessageBox.Show("不存在可以解析的配置文件！");
                        return;
                    }

                    // 检查 USB 列表是否有效
                    if (usbList.Count <= 0)
                    {
                        // WaitBefore.Close();
                        DevExpress.XtraEditors.XtraMessageBox.Show("无法解析Bin文件！请联系管理员！");
                        return;
                    }

                    registerBinValues = BinUtilsHelp.GetAddrValData(BinList, usbList, _width, _height);
                    DevExpress.XtraEditors.XtraMessageBox.Show("获取Bin对应文件 成功！ ");
                }

            }
            catch (Exception ex)
            {
                DevExpress.XtraEditors.XtraMessageBox.Show(ex.ToString());
            }
            
        }

        private void simpleButton6_Click(object sender, EventArgs e)
        {

            #region 测试代码

            //if (registerBinValues.Count > 0 && registerCommonValues.Count > 0 && registerSettingValues.Count >0)
            //{
            //    // 准备写入文件
            //    string directoryPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Lib", "xc151_Bin");
            //    if (!Directory.Exists(directoryPath))
            //    {
            //        Directory.CreateDirectory(directoryPath); // 确保目录存在
            //    }

            //    string filePath = Path.Combine(directoryPath, "comparisonResults.txt");


            //    // 写入不同的文件
            //    string binResultsFilePath = Path.Combine(directoryPath, "BinResults.txt");
            //    string settingResultsFilePath = Path.Combine(directoryPath, "SettingResults.txt");

            //    // 对 registerBinValues 按照地址进行排序
            //    var sortedBinValues = registerBinValues.OrderBy(r => r.Address).ToList();
            //    // 写入 BinResults.txt
            //    using (StreamWriter writer = new StreamWriter(binResultsFilePath))
            //    {
            //        writer.WriteLine("Sorted registerBinValues:");
            //        foreach (var item in sortedBinValues)
            //        {
            //            writer.WriteLine($"地址: 0x{item.Address:X}, 值: 0x{item.Value:X}");
            //        }
            //    }
            //    // 对 registerBinValues 按照地址进行排序
            //    var sortedSettingValues = registerValues.OrderBy(r => r.Address).ToList();

            //    // 写入 SettingResults.txt
            //    using (StreamWriter writer = new StreamWriter(settingResultsFilePath))
            //    {
            //        writer.WriteLine("Sorted registerSettingValues:");
            //        foreach (var item in sortedSettingValues)
            //        {
            //            writer.WriteLine($"地址: 0x{item.Address:X}, 值: 0x{item.Value:X}");
            //        }
            //    }



            //    DevExpress.XtraEditors.XtraMessageBox.Show("赋值Bin文件 成功！ 关闭后将打开对应文件夹！");

            //    // 打开文件夹
            //    try
            //    {
            //        System.Diagnostics.Process.Start("explorer.exe", directoryPath);
            //    }
            //    catch (Exception ex)
            //    {
            //        DevExpress.XtraEditors.XtraMessageBox.Show("打开文件夹时出错: " + ex.Message);
            //    }
            //} 
            #endregion


            // 检查输入列表的有效性
            if (AreListsInvalid(registerBinValues, registerCommonValues, registerSettingValues))
            {
                DevExpress.XtraEditors.XtraMessageBox.Show("检查Bin 或者 IQ_Common 或者Setting 文件 缺失！");
                return; // 返回如果任一列表无效
            }

            // 存储未匹配到的 Bin 值
            List<RegisterValue> binTemp = new List<RegisterValue>();

            // 更新 Common 值和 Setting 值
            UpdateRegisterValues(registerBinValues, registerCommonValues, registerSettingValues, binTemp);

            // 将结果写入文件
            WriteRegisterValuesToFile(registerCommonValues, "registerCommonValues.txt");
            WriteRegisterValuesToFile(registerSettingValues, "registerSettingValues.txt");

            // 生成 Bin 转换到 Setting 的报告
            WriteBinToSettingReport(binTemp, registerCommonValues, registerSettingValues);

            DevExpress.XtraEditors.XtraMessageBox.Show("更新完成！ 请查看桌面！");
        }

        // 检查输入列表是否有效
        private bool AreListsInvalid(params List<RegisterValue>[] lists)
        {
            return lists.Any(list => list == null || list.Count == 0); // 如果任一列表为 null 或空，则返回 true
        }
        // 更新指定寄存器值的方法
        private void UpdateRegisterValues(List<RegisterValue> binValues, List<RegisterValue> targetCommonValues, List<RegisterValue> targetSettingValues, List<RegisterValue> binTemp)
        {
            foreach (var binItem in binValues) // 遍历 Bin 值
            {
                // 获取所有匹配的目标值
                var matchingTargetcItems = targetCommonValues.Where(t => t.Address == binItem.Address).ToList();
                var matchingTargetsItems = targetSettingValues.Where(t => t.Address == binItem.Address).ToList();
                //先判断两个是否有一个找到了 就认为地址找到了 就需要更新
                if (matchingTargetcItems.Any()|| matchingTargetsItems.Any()) // 如果找到匹配项
                {
                    if (matchingTargetcItems.Any())
                    {
                        foreach (var targetItem in matchingTargetcItems)
                        {
                            targetItem.NewVal = binItem.Value; // 更新目标寄存器的新值
                            UpdateNoteFromValue(targetItem); // 更新目标寄存器的注释
                        }
                    }
                    if (matchingTargetsItems.Any())
                    {
                        foreach (var targetItem in matchingTargetsItems)
                        {
                            targetItem.NewVal = binItem.Value; // 更新目标寄存器的新值
                            UpdateNoteFromValue(targetItem); // 更新目标寄存器的注释
                        }
                    }
                }
                else
                {
                    // 如果未匹配到 Common 或 Setting，检查 binTemp 中是否已包含相同地址的项
                    if (!binTemp.Any(item => item.Address == binItem.Address))
                    {
                        binTemp.Add(binItem); // 如果 binTemp 中没有相同地址，则添加到 binTemp
                    }
                }
            }
        }
        // 更新寄存器值注释的方法
        private void UpdateNoteFromValue(RegisterValue item)
        {
            string pattern = @"0x([0-9a-fA-F]+),0x([0-9a-fA-F]+)"; // 正则模式，用于匹配寄存器注释中的地址和原始值
            Match match = Regex.Match(item.Note, pattern);
            if (match.Success) // 如果匹配成功
            {
                string valueHex = match.Groups[2].Value; // 提取原始值
                item.NewNote = item.Note.Replace($"0x{valueHex}", $"0x{item.NewVal:X2}"); // 替换为新值
            }
        }

        // 生成从 Bin 到 Setting 的报告
        private void WriteBinToSettingReport(List<RegisterValue> binTemp, List<RegisterValue> registerCommonValues, List<RegisterValue> registerSettingValues)
        {
            string desktopPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "BinToSettingReport.txt"); // 报告文件路径
            using (StreamWriter writer = new StreamWriter(desktopPath)) // 使用 StreamWriter 写入文件
            {
                writer.WriteLine($"Bin转换到Setting 报告");
                writer.WriteLine("\n\n");
                writer.WriteLine("Bin中存在，在Setting或者Common 中未找到的寄存器和值");

                // 输出未找到的 Bin 值
                foreach (var item in binTemp)
                {
                    writer.WriteLine($"0x{item.Address:X},0x{item.Value:X}");
                }

                writer.WriteLine("\n\n");
                writer.WriteLine("Setting中未更新到寄存器");
                // 输出未更新的 Setting 值
                foreach (var item in registerSettingValues.Where(c => string.IsNullOrEmpty(c.NewNote)))
                {
                    if (item.Note.StartsWith("//")||item.Note.Contains("0xfffd")||item.Note.Contains("0xfffe"))
                    {
                        continue;
                    }
                    writer.WriteLine($"{item.Note}");
                }

                writer.WriteLine("\n\n");
                writer.WriteLine("Common中未更新到寄存器");
                // 输出未更新的 Common 值
                foreach (var item in registerCommonValues.Where(c => string.IsNullOrEmpty(c.NewNote)))
                {
                    if (item.Note.StartsWith("//") || item.Note.Contains("0xfffd") || item.Note.Contains("0xfffe"))
                    {
                        continue;
                    }
                    writer.WriteLine($"{item.Note}");
                }
            }
        }

        // 将寄存器值写入文件的方法
        private void WriteRegisterValuesToFile(List<RegisterValue> registerValues, string fileName)
        {
            string desktopPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName); // 文件路径
            using (StreamWriter writer = new StreamWriter(desktopPath)) // 使用 StreamWriter 写入文件
            {
                foreach (var item in registerValues)
                {
                    // 写入新注释或旧注释
                    string line = !string.IsNullOrEmpty(item.NewNote) ? item.NewNote : item.Note;
                    writer.WriteLine(line);
                }
            }
        }

    }

    
}